package github.flandre.examplemod.common.energy.block;

import com.google.common.collect.Maps;
import com.mojang.datafixers.DSL;
import github.flandre.examplemod.common.energy.SimpleEnergyNetwork;
import github.flandre.examplemod.common.energy.tileentity.FEDemoMachineTileEntity;
import github.flandre.examplemod.common.energy.tileentity.FEDemoWireTileEntity;
import github.flandre.examplemod.core.init.Itemgroup.ExampleGroup;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.profiler.IProfiler;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.Property;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.registries.ObjectHolder;

import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.Map;

@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class FEDemoWireBlock extends Block
{
    public static final String NAME = "examplemod:wire";

    @ObjectHolder(NAME)
    public static FEDemoWireBlock BLOCK;

    @SubscribeEvent
    public static void onRegisterBlock(@Nonnull RegistryEvent.Register<Block> event)
    {
        event.getRegistry().register(new FEDemoWireBlock().setRegistryName(NAME));
    }

    @SubscribeEvent
    public static void onRegisterItem(@Nonnull RegistryEvent.Register<Item> event)
    {
        event.getRegistry().register(new BlockItem(BLOCK, new Item.Properties().group(ExampleGroup.exampleGroup)).setRegistryName(NAME));
    }

    private FEDemoWireBlock()
    {
        super(Block.Properties.create(Material.GLASS).hardnessAndResistance(2));
    }

    @Override
    public boolean hasTileEntity(@Nonnull BlockState state)
    {
        return true;
    }

    @Override
    public TileEntity createTileEntity(@Nonnull BlockState state, @Nonnull IBlockReader world)
    {
        return FEDemoWireTileEntity.TILE_ENTITY_TYPE.create();
    }

    //方块状态
    public static final Map<Direction, BooleanProperty> PROPERTY_MAP;

    static
    {
        Map<Direction, BooleanProperty> map = Maps.newEnumMap(Direction.class);
        map.put(Direction.NORTH, BlockStateProperties.NORTH);
        map.put(Direction.EAST, BlockStateProperties.EAST);
        map.put(Direction.SOUTH, BlockStateProperties.SOUTH);
        map.put(Direction.WEST, BlockStateProperties.WEST);
        map.put(Direction.UP, BlockStateProperties.UP);
        map.put(Direction.DOWN, BlockStateProperties.DOWN);
        PROPERTY_MAP = Collections.unmodifiableMap(map); //对map对象的深拷贝
    }

    //声明该方块拥有以上全部六个属性：
    @Override
    protected void fillStateContainer(@Nonnull StateContainer.Builder<Block, BlockState> builder)
    {
        builder.add(PROPERTY_MAP.values().toArray(new Property<?>[0]));
        super.fillStateContainer(builder);
    }

    //调整方块状态
    @Override
    public BlockState getStateForPlacement(@Nonnull BlockItemUseContext context)
    {
        BlockState state = this.getDefaultState();
        for (Direction facing : Direction.values())
        {
            World world = context.getWorld();
            BlockPos facingPos = context.getPos().offset(facing);
            BlockState facingState = world.getBlockState(facingPos);
            state = state.with(PROPERTY_MAP.get(facing), this.canConnect(world, facing.getOpposite(), facingPos, facingState));
        }
        return state;
    }


    //在该方块周围的方块发生变动时调整方块状态
    @Nonnull
    @Override
    @SuppressWarnings("deprecation")
    public BlockState updatePostPlacement(@Nonnull BlockState state, @Nonnull Direction facing, @Nonnull BlockState facingState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos facingPos)
    {
        return state.with(PROPERTY_MAP.get(facing), this.canConnect(world, facing.getOpposite(), facingPos, facingState));
    }

    //检查连接的是不是我们的导线
    //检查连接的方块是否有能量相关的 Capability
    private boolean canConnect(@Nonnull IWorld world, @Nonnull Direction facing, @Nonnull BlockPos pos, @Nonnull BlockState state)
    {
        if (!state.getBlock().equals(BLOCK))
        {
            TileEntity tileEntity = world.getTileEntity(pos);
            return tileEntity != null && tileEntity.getCapability(CapabilityEnergy.ENERGY, facing).isPresent();
        }
        return true;
    }

    //碰撞箱
    @Nonnull
    @Override
    @SuppressWarnings("deprecation")
    public VoxelShape getCollisionShape(@Nonnull BlockState state, @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull ISelectionContext context)
    {
        return Block.makeCuboidShape(4, 4, 4, 12, 12, 12);
    }

    //选择框
    @Nonnull
    @Override
    @SuppressWarnings("deprecation")
    public VoxelShape getShape(@Nonnull BlockState state, @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull ISelectionContext context)
    {
        return Block.makeCuboidShape(4, 4, 4, 12, 12, 12);
    }

    @Override
    @SuppressWarnings("deprecation")
    public void neighborChanged(@Nonnull BlockState state, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Block fromBlock, @Nonnull BlockPos fromPos, boolean isMoving)
    {
        if (!world.isRemote)
        {
            TileEntity tileEntity = world.getTileEntity(pos);
            if (tileEntity instanceof FEDemoWireTileEntity)
            {
                SimpleEnergyNetwork.Factory.get(world).enableBlock(pos, tileEntity::markDirty);
            }
        }
    }

}
